#ifndef PRIVATE_WUJI_H_INCLUDED
#define PRIVATE_WUJI_H_INCLUDED
#include <stdio.h>
#include <setjmp.h>
#include "MEM.h"
#include "WJ.h"
#include "WJ_dev.h"

#define smaller(a, b)	((a) < (b) ? (a) : (b))
#define larger(a, b)	((a) > (b) ? (a) : (b))


#define MESSAGE_ARGUMENT_MAX    (256)
#define LINE_BUF_SIZE           (1024)
#define STACK_ALLOC_SIZE        (256)
#define ARRAY_ALLOC_SIZE        (256)
#define HEAP_THRESHOLD_SIZE     (1024 * 256)
#define LONGJMP_ARG				(1)
#define REGEXP_GROUP_INDEX_MAX_COLUMN	(3)

#define EXCEPTION_MEMBER_MESSAGE		("message")
#define EXCEPTION_MEMBER_STACK_TRACE    ("stack_trace")
#define EXCEPTION_MEMBER_LINE_NUMBER	("line_number")
#define EXCEPTION_MEMBER_FUNCTION_NAME	("function_name")
#define EXCEPTION_MEMBER_PRINT_STACK_TRACE	("print_stack_trace")
#define EXCEPTION_CREATE_METHOD_NAME	("create")

#define ARRAY_ITERATOR_METHOD_NAME		("__create_array_iterator")
#define ITERATOR_METHOD_NAME			("迭代")
#define IS_DONE_METHOD_NAME				("is_done")
#define NEXT_METHOD_NAME				("next")
#define CURRENT_ITEM_METHOD_NAME		("current_item")

#define ARRAY_SIZE(array)		(sizeof(array) / sizeof((array)[0]))


typedef enum {
    PARSE_ERR = 1,
    CHARACTER_INVALID_ERR,
    FUNCTION_MULTIPLE_DEFINE_ERR,
    BAD_MULTIBYTE_CHARACTER_IN_COMPILE_ERR,
    CR_IN_REGEXP_ERR,
    CAN_NOT_CREATE_REGEXP_IN_COMPILE_ERR,
    UNEXPECTED_WIDE_STRING_IN_COMPILE_ERR,
    ARRAY_ELEMENT_CAN_NOT_BE_FINAL_ERR,
    COMPLEX_ASSIGNMENT_OPERATOR_TO_FINAL_ERR,
    COMPILE_ERROR_COUNT_PLUS_1
} CompileError;

typedef enum {
    VARIABLE_NOT_FOUND_ERR = 1,
    ARGUMENT_TOO_MANY_ERR,
    ARGUMENT_TOO_FEW_ERR,
    NOT_BOOLEAN_TYPE_ERR,
    MINUS_OPERAND_TYPE_ERR,
    BAD_OPERAND_TYPE_ERR,
    LOGICAL_OP_DOUBLE_OPERAND_ERR,
    LOGICAL_OP_INTEGER_OPERAND_ERR,
    NOT_BOOLEAN_OPERATOR_ERR,
    NOT_NULL_OPERATOR_ERR,
    NOT_LVALUE_ERR,
    INDEX_OPERAND_NOT_ARRAY_ERR,
    INDEX_OPERAND_NOT_INT_ERR,
    ARRAY_INDEX_OUT_OF_BOUNDS_ERR,
    NO_SUCH_METHOD_ERR,
    INC_DEC_OPERAND_TYPE_ERR,
    INC_DEC_OPERAND_NOT_EXIST_ERR,
    NOT_FUNCTION_ERR,
    NOT_OBJECT_MEMBER_UPDATE_ERR,
    NOT_OBJECT_MEMBER_ASSIGN_ERR,
    NO_SUCH_MEMBER_ERR,
    NO_MEMBER_TYPE_ERR,
    BAD_OPERATOR_FOR_STRING_ERR,
    DIVISION_BY_ZERO_ERR,
    GLOBAL_VARIABLE_NOT_FOUND_ERR,
    GLOBAL_STATEMENT_IN_TOPLEVEL_ERR,
    FUNCTION_EXISTS_ERR,
    ARRAY_RESIZE_ARGUMENT_ERR,
    ARRAY_INSERT_ARGUMENT_ERR,
    ARRAY_REMOVE_ARGUMENT_ERR,
    STRING_POS_OUT_OF_BOUNDS_ERR,
    STRING_SUBSTR_LEN_ERR,
    STRING_SUBSTR_ARGUMENT_ERR,
    EXCEPTION_HAS_NO_MESSAGE_ERR,
    EXCEPTION_MESSAGE_IS_NOT_STRING_ERR,
    EXCEPTION_HAS_NO_STACK_TRACE_ERR,
    STACK_TRACE_IS_NOT_ARRAY_ERR,
    STACK_TRACE_LINE_IS_NOT_ASSOC_ERR,
    STACK_TRACE_LINE_HAS_NO_LINE_NUMBER_ERR,
    STACK_TRACE_LINE_HAS_NO_FUNC_NAME_ERR,
    EXCEPTION_IS_NOT_ASSOC_ERR,
    EXCEPTION_HAS_NO_PRINT_STACK_TRACE_METHOD_ERR,
    PRINT_STACK_TRACE_IS_NOT_CLOSURE_ERR,
    BAD_MULTIBYTE_CHARACTER_ERR,
    EXCEPTION_CLASS_IS_NOT_ASSOC_ERR,
    EXCEPTION_CLASS_HAS_NO_CREATE_METHOD_ERR,
    ARGUMENT_TYPE_MISMATCH_ERR,
    UNEXPECTED_WIDE_STRING_ERR,
    ONIG_SEARCH_FAIL_ERR,
    GROUP_INDEX_OVERFLOW_ERR,
    NO_SUCH_GROUP_INDEX_ERR,
    BREAK_OR_CONTINUE_REACHED_TOPLEVEL_ERR,
    ASSIGN_TO_FINAL_VARIABLE_ERR,
    FUNCTION_NOT_FOUND_ERR,
    RUNTIME_ERROR_COUNT_PLUS_1
} RuntimeError;

typedef struct Expression_tag Expression;

typedef enum {
    BOOLEAN_EXPRESSION = 1,	/* 布尔型常量 */
    INT_EXPRESSION,			/* 整数型常量 */
    DOUBLE_EXPRESSION,		/* 实数型常量 */
    STRING_EXPRESSION,		/* 字符串型常量 */
	REGEXP_EXPRESSION,
    IDENTIFIER_EXPRESSION,	/* 变量 */
	COMMA_EXPRESSION,
    ASSIGN_EXPRESSION,		/* 赋值表达式 */
    ADD_EXPRESSION,			/* 加法表达式 */
    SUB_EXPRESSION,			/* 减法表达式 */
    MUL_EXPRESSION,			/* 乘法表达式 */
    DIV_EXPRESSION,			/* 除法表达式 */
    MOD_EXPRESSION,			/* 求余表达式 */
    EQ_EXPRESSION,			/* == */
    NE_EXPRESSION,			/* != */
    GT_EXPRESSION,			/* > */
    GE_EXPRESSION,			/* >= */
    LT_EXPRESSION,			/* < */
    LE_EXPRESSION,			/* <= */
    LOGICAL_AND_EXPRESSION,	/* && */
    LOGICAL_OR_EXPRESSION,	/* || */
    MINUS_EXPRESSION,		/* 单目取负 */
	LOGICAL_NOT_EXPRESSION,
    FUNCTION_CALL_EXPRESSION,/* 函数调用表达式 */
	MEMBER_EXPRESSION,
    METHOD_CALL_EXPRESSION,
    NULL_EXPRESSION,		/* null表达式 */
    ARRAY_EXPRESSION,
    INDEX_EXPRESSION,
    INCREMENT_EXPRESSION,
    DECREMENT_EXPRESSION,
	CLOSURE_EXPRESSION,
    EXPRESSION_TYPE_COUNT_PLUS_1
} ExpressionType;

#define wj_is_numeric_type(type)\
	((type) == WJ_INT_VALUE || (type) == WJ_DOUBLE_VALUE)
#define wj_is_math_operator(operator) \
  ((operator) == ADD_EXPRESSION || (operator) == SUB_EXPRESSION\
   || (operator) == MUL_EXPRESSION || (operator) == DIV_EXPRESSION\
   || (operator) == MOD_EXPRESSION)

#define wj_is_compare_operator(operator) \
  ((operator) == EQ_EXPRESSION || (operator) == NE_EXPRESSION\
   || (operator) == GT_EXPRESSION || (operator) == GE_EXPRESSION\
   || (operator) == LT_EXPRESSION || (operator) == LE_EXPRESSION)

#define wj_is_logical_operator(operator) \
  ((operator) == LOGICAL_AND_EXPRESSION || (operator) == LOGICAL_OR_EXPRESSION)

typedef struct ArgumentList_tag {
    Expression				*expression;
    struct ArgumentList_tag *next;
} ArgumentList;

typedef struct {
	Expression *left;
	Expression *right;
} CommaExpression;

typedef enum {
	NORMAL_ASSIGN = 1,
	ADD_ASSIGN,
	SUB_ASSIGN,
	MUL_ASSIGN,
	DIV_ASSIGN,
	MOD_ASSIGN
} AssignmentOperator;

typedef struct {
	WJ_Boolean	is_final;
	AssignmentOperator	operator;
    Expression  *left;
    Expression  *operand;
} AssignExpression;

typedef struct {
    Expression  *left;
    Expression  *right;
} BinaryExpression;

typedef struct {
/*     char                *identifier; */
	Expression			*function;
    ArgumentList        *argument;
} FunctionCallExpression;

typedef struct ExpressionList_tag {
    Expression					*expression;
    struct ExpressionList_tag	*next;
} ExpressionList;

typedef struct {
    Expression  *array;
    Expression  *index;
} IndexExpression;

typedef struct {
	Expression		*expression;
	char			*member_name;
} MemberExpression;

typedef struct {
    Expression  *operand;
} IncrementOrDecrement;

typedef struct {
	FunctionDefinition	*function_definition;
} ClosureExpression;

struct Expression_tag {
    ExpressionType	type;
    int				line_number;
    union {
        WJ_Boolean				boolean_value;
        int                     int_value;
        double                  double_value;
        char                    *string_value;
        char                    *identifier;
		CommaExpression			comma;
        AssignExpression        assign_expression;
        BinaryExpression        binary_expression;
        Expression              *minus_expression;
        Expression              *logical_not;
        FunctionCallExpression  function_call_expression;
		MemberExpression		member_expression;
/*         MethodCallExpression    method_call_expression; */
        ExpressionList          *array_literal;
        IndexExpression         index_expression;
        IncrementOrDecrement    inc_dec;
		ClosureExpression		closure;
    } u;
};

typedef struct Statement_tag Statement;

typedef struct StatementList_tag {
    Statement					*statement;
    struct StatementList_tag    *next;
} StatementList;

/* typedef struct { */
/*     StatementList       *statement_list;	[> 语句链表 <] */
/* } Block; */
struct WJ_Block_tag {
	StatementList		*statement_list;
};

typedef struct IdentifierList_tag {
    char						*name;
    struct IdentifierList_tag	*next;
} IdentifierList;

typedef struct {
    IdentifierList      *identifier_list;
} GlobalStatement;

typedef struct Elsif_tag {
    Expression			*condition;
    Block				*block;
    struct Elsif_tag    *next;
} Elsif;

typedef struct {
    Expression  *condition;
    Block       *then_block;
    Elsif       *elsif_list;
    Block       *else_block;
} IfStatement;

typedef struct {
	char		*label;
    Expression  *condition;
    Block       *block;
} WhileStatement;

typedef struct {
	char		*label;
    Expression  *init;
    Expression  *condition;
    Expression  *post;
    Block       *block;
} ForStatement;

typedef struct {
	char		*label;
	char		*variable;
	Expression	*collection;
	Block		*block;
} ForeachStatement;

typedef struct {
    Expression *return_value;
} ReturnStatement;

typedef struct {
	char 		*label;
} BreakStatement;

typedef struct {
	char		*label;
} ContinueStatement;

typedef struct {
	Block	*try_block;
	Block	*catch_block;
	char	*exception;
	Block	*finally_block;
} TryStatement;

typedef struct {
	Expression *exception;
} ThrowStatement;

typedef enum {
    EXPRESSION_STATEMENT = 1,
    GLOBAL_STATEMENT,
    IF_STATEMENT,
    WHILE_STATEMENT,
    FOR_STATEMENT,
	FOREACH_STATEMENT,
    RETURN_STATEMENT,
    BREAK_STATEMENT,
    CONTINUE_STATEMENT,
	THROW_STATEMENT,
    STATEMENT_TYPE_COUNT_PLUS_1
} StatementType;

struct Statement_tag {
    StatementType       type;
    int                 line_number;
    union {
        Expression      	*expression_s;
        GlobalStatement		global_s;
        IfStatement     	if_s;
        WhileStatement  	while_s;
        ForStatement    	for_s;
		ForeachStatement	foreach_s;
		BreakStatement		break_s;
		ContinueStatement	continue_s;
        ReturnStatement 	return_s;
		TryStatement		try_s;
		ThrowStatement		throw_s;
    } u;
};

/* typedef struct ParameterList_tag { */
/*     char						*name;	[> 变量名 <] */
/*     struct ParameterList_tag	*next;	[> 链表所用的指针 <] */
/* } ParameterList; */
struct WJ_ParameterList_tag {
	char			*name;
	struct WJ_ParameterList_tag *next;
};

typedef struct Variable_tag {
	WJ_Boolean			is_final;
    char				*name;	/* 变量名 */
    WJ_Value			value;	/* 变量值 */
    struct Variable_tag *next;	/* 指向下一个变量的指针 */
} Variable;

typedef enum {
    NORMAL_STATEMENT_RESULT = 1,
    RETURN_STATEMENT_RESULT,
    BREAK_STATEMENT_RESULT,
    CONTINUE_STATEMENT_RESULT,
    STATEMENT_RESULT_TYPE_COUNT_PLUS_1
} StatementResultType;

typedef struct {
    StatementResultType type;
    union {
        WJ_Value		return_value;
		char			*label;
    } u;
} StatementResult;

typedef struct GlobalVariableRef_tag {
	char							*name;
    Variable						*variable;
    struct GlobalVariableRef_tag	*next;
} GlobalVariableRef;

typedef struct RefInNativeFunc_tag {
    WJ_Object					*object;
    struct RefInNativeFunc_tag	*next;
} RefInNativeFunc;

struct WJ_LocalEnvironment_tag {
	char				*current_function_name;
	int					caller_line_number;
    WJ_Object			*variable;
    GlobalVariableRef	*global_variable;
    RefInNativeFunc     *ref_in_native_method;
    struct WJ_LocalEnvironment_tag *next;
};

typedef struct {
    int         stack_alloc_size;
    int         stack_pointer;
    WJ_Value	*stack;
} Stack;

typedef struct {
    int         current_heap_size;
    int         current_threshold;
    WJ_Object	*header;
} Heap;

typedef struct {
	jmp_buf		environment;
} RecoveryEnvironment;

typedef enum {
	EUC_ENCODING = 1,
	SHIFT_JIS_ENCODING,
	UTF_8_ENCODING
} Encoding;

struct WJ_Interpreter_tag {	/* wuji解释器使用结构体，本身对a外是隐藏的 */
    MEM_Storage				interpreter_storage;	/* 与解释器相同寿命的存储器 */
    MEM_Storage				execute_storage;		/* 运行时使用的存储器 */
    Variable				*variable;				/* 全局变量链表 */
    FunctionDefinition		*function_list;			/* 函数定义链表 */
    StatementList			*statement_list;		/* 语句链表，所有的执行语句都保存在此 */
    int						current_line_number;	/* 编译时当前的行号，用于错误时提示 */
    Stack					stack;
    Heap					heap;
    WJ_LocalEnvironment		*top_environment;
	WJ_Value				current_exception;
	RecoveryEnvironment		current_recovery_environment;
};

struct WJ_Array_tag {
    int         size;
    int         alloc_size;
    WJ_Value	*array;
};

struct WJ_String_tag {
    WJ_Boolean	is_literal;
    char        *string;
};

typedef struct {
	char		*name;
	WJ_Value	value;
	WJ_Boolean	is_final;
} AssocMember;

struct WJ_Assoc_tag {
	int			member_count;
	AssocMember	*member;
};

typedef struct {
	WJ_Object	*frame;
	WJ_Object	*next;
} ScopeChain;

typedef struct {
	void		*pointer;
	WJ_NativePointerInfo	*info;
} NativePointer;

typedef enum {
    ARRAY_OBJECT = 1,
    STRING_OBJECT,
	ASSOC_OBJECT,
	SCOPE_CHAIN_OBJECT,
	NATIVE_POINTER_OBJECT,
    OBJECT_TYPE_COUNT_PLUS_1
} ObjectType;

#define wj_is_object_value(type) \
  ((type) == WJ_STRING_VALUE || (type) == WJ_ARRAY_VALUE\
   || (type) == WJ_ASSOC_VALUE || (type) == WJ_NATIVE_POINTER_VALUE\
   || (type) == WJ_SCOPE_CHAIN_VALUE)

struct WJ_Object_tag {
    ObjectType			type;
    unsigned int		marked:1;
    union {
        WJ_Array		array;
        WJ_String		string;
		WJ_Assoc		assoc;
		ScopeChain		scope_chain;
		NativePointer	native_pointer;
    } u;
    struct WJ_Object_tag *prev;
    struct WJ_Object_tag *next;
};

typedef struct {
    char        *string;
} VString;


/* create.c */
void wj_function_define(char *identifier, ParameterList *parameter_list, Block *block);
ParameterList *wj_create_parameter(char *identifier);
ParameterList *wj_chain_parameter(ParameterList *list, char *identifier);
ArgumentList *wj_create_argument_list(Expression *expression);
ArgumentList *wj_chain_argument_list(ArgumentList *list, Expression *expr);
ExpressionList *wj_create_expression_list(Expression *expression);
ExpressionList *wj_chain_expression_list(ExpressionList *list, Expression *expr);
StatementList *wj_create_statement_list(Statement *statement);
StatementList *wj_chain_statement_list(StatementList *list, Statement *statement);
Expression *wj_alloc_expression(ExpressionType type);
Expression *wj_create_comma_expression(Expression *left, Expression *right);
Expression *wj_create_assign_expression(WJ_Boolean is_final, Expression *left, AssignmentOperator operator, Expression *operand);
Expression *wj_create_binary_expression(ExpressionType operator, Expression *left, Expression *right);
Expression *wj_create_minus_expression(Expression *operand);
Expression *wj_create_logical_not_expression(Expression *operand);
Expression *wj_create_index_expression(Expression *array, Expression *index);
Expression *wj_create_incdec_expression(Expression *operand, ExpressionType inc_or_dec);
Expression *wj_create_identifier_expression(char *identifier);
Expression *wj_create_function_call_expression(Expression *func_name, ArgumentList *argument);
Expression *
wj_create_member_expression(Expression *expression, char *member_name);
/* Expression *wj_create_method_call_expression(Expression *expression, char *method_name, ArgumentList *argument); */
Expression *wj_create_boolean_expression(WJ_Boolean value);
Expression *wj_create_null_expression(void);
Statement *wj_create_global_statement(IdentifierList *identifier_list);
IdentifierList *wj_create_global_identifier(char *identifier);
IdentifierList *wj_chain_identifier(IdentifierList *list, char *identifier);
Expression *wj_create_array_expression(ExpressionList *list);
Expression *
wj_create_closure_definition(char *identifier,
							ParameterList *parameter_list,
							Block *block);

Statement *wj_create_if_statement(Expression *condition, Block *then_block, Elsif *elsif_list, Block *else_block);
Elsif *wj_chain_elsif_list(Elsif *list, Elsif *add);
Elsif *wj_create_elsif(Expression *expr, Block *block);
Statement *wj_create_while_statement(Expression *condition, Block *block);
Statement *wj_create_for_statement(Expression *init, Expression *cond, Expression *post, Block *block);
Statement *
wj_create_foreach_statement(char *label, char *variable,
							Expression *collection, Block *block);

Block *wj_create_block(StatementList *statement_list);
Statement *wj_create_expression_statement(Expression *expression);
Statement *wj_create_return_statement(Expression *expression);
Statement *wj_create_break_statement(void);
Statement *wj_create_continue_statement(void);
Statement *wj_create_throw_statement(Expression *expression);

/* string.c */
char *wj_create_identifier(char *str);
void wj_open_string_literal(void);
void wj_add_string_literal(int letter);
void wj_reset_string_literal_buffer(void);
char *wj_close_string_literal(void);

/* execute.c */
StatementResult
wj_execute_statement_list(WJ_Interpreter *inter,WJ_LocalEnvironment *env, StatementList *list);

/* eval.c */
int wj_get_stack_pointer(WJ_Interpreter *inter);
void 
wj_set_stack_pointer(WJ_Interpreter *inter, int stack_pointer);
WJ_Value *
wj_get_identifier_lvalue(WJ_Interpreter *inter, WJ_LocalEnvironment *env,
	                     	int line_number, char *identifier);
WJ_Value
wj_eval_binary_expression(WJ_Interpreter *inter, WJ_LocalEnvironment *env,
                           ExpressionType operator,
                           Expression *left, Expression *right);
WJ_Value
wj_eval_minus_expression(WJ_Interpreter *inter, WJ_LocalEnvironment *env,
                          Expression *operand);
WJ_Value
wj_eval_expression(WJ_Interpreter *inter, WJ_LocalEnvironment *env,
                    Expression *expr);
WJ_Value *
wj_eval_and_peek_expression(WJ_Interpreter *inter, WJ_LocalEnvironment *env,
							Expression *expr);


/* heap.c */
WJ_Object *
wj_create_wuji_string_i(WJ_Interpreter *inter, char *str);
WJ_Object *
wj_create_array_i(WJ_Interpreter *inter, int size);
WJ_Object *
wj_create_assoc_i(WJ_Interpreter *inter);
WJ_Object *
wj_literal_to_wj_string_i(WJ_Interpreter *inter, char *str);
WJ_Object *
wj_string_substr_i(WJ_Interpreter *inter, WJ_LocalEnvironment *env, 
				WJ_Object *str, int from, int len, int line_number);
WJ_Object *
wj_create_native_pointer_i(WJ_Interpreter *inter, void *pointer,
							WJ_NativePointerInfo *info);
WJ_Object *
wj_create_scope_chain(WJ_Interpreter *inter);
void
wj_garbage_collect(WJ_Interpreter *inter);



/* util.c */
WJ_Interpreter *wj_get_current_interpreter(void);
void wj_set_current_interpreter(WJ_Interpreter *inter);
void *wj_malloc(size_t size);
void *wj_execute_malloc(WJ_Interpreter *inter, size_t size);
Variable *wj_search_global_variable(WJ_Interpreter *inter, char *identifier);
char *wj_get_operator_string(ExpressionType type);
void wj_vstr_clear(VString *v);
void wj_vstr_append_string(VString *v, char *str);
void wj_vstr_append_character(VString *v, int ch);


/* error.c */
void wj_compile_error(CompileError id, ...);
void wj_runtime_error(int line_number, RuntimeError id, ...);

/* native.c */
void add_native_functions(WJ_Interpreter *inter);
void wj_add_std_fp(WJ_Interpreter *inter);





#endif /* PRIVATE_WUJI_H_INCLUDED */
